package com.learn.rpc.version.version5;

import com.learn.rpc.common.FinalParam;
import com.learn.rpc.common.IAdminUserService;

import java.io.IOException;
import java.io.ObjectInput;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.net.Socket;

/**
 * 通过代理和反射的方式实现任意接口类的方法远程调用,需要在服务端维护接口的实现类对应表
 *
 * @author wangxing
 * @version 2020/8/15 7:03 Administrator
 */
public class RpcClient {
    public static void main(String[] args) throws IOException {
        IAdminUserService service = (IAdminUserService) Stud.getStud(IAdminUserService.class);
        System.out.println(service.findAdminUserById(123));
        System.out.println(service.findAdminUserByName("wangxing"));
        System.out.println(service.getNameAndId(123, "wangxing"));
    }
}

class Stud {

    public static Object getStud(Class clazz) {
        InvocationHandler h = new InvocationHandler() {
            @Override
            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                Object result = null;
                Socket socket = new Socket(FinalParam.HOST,FinalParam.PORT);
                String className = clazz.getName();
                String methodName = method.getName();

                Class<?>[] parameterTypes = method.getParameterTypes();
                ObjectOutputStream objectOutputStream = new ObjectOutputStream(socket.getOutputStream());
//                传递类名
                objectOutputStream.writeUTF(className);
//                传递方法名
                objectOutputStream.writeUTF(methodName);
//                传递参数类型
                objectOutputStream.writeObject(parameterTypes);
//                传递参数
                objectOutputStream.writeObject(args);

                ObjectInputStream objectInputStream = new ObjectInputStream(socket.getInputStream());
                result = objectInputStream.readObject();

                objectOutputStream.close();
                socket.close();

                return result;
            }
        };
        Object service = Proxy.newProxyInstance(clazz.getClassLoader(), new Class[]{clazz}, h);

        return service;
    }
}
